using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using System.Collections;

namespace FutureCorePlugin
{
    public class CurveScroll : MonoBehaviour
    {
        public GridLayoutGroup grid;
        private Vector3 center;
        public RectTransform Content;
        private RectTransform viewPort;
        public ScrollRect scroll;
        public int CanViewNum;
        [HideInInspector]
        public float OffSetFrom = 1200;
        /// <summary>
        /// 显示的ItemList
        /// </summary>
        public List<RectTransform> ActiveList;
        public List<RectTransform> InActiveList = new List<RectTransform>();
        public List<RectTransform> AllItemList = new List<RectTransform>();
        public Vector3 CenterOffset;
        public float LineCurveWidth;
        private float CanvasScale;
        float ItemOffset_X;
        public GameObject Test;
        public bool IsTest = false;
        public bool IsEditor = false;
        public int TestCount;
        private void Awake()
        {
            scroll = transform.GetComponent<ScrollRect>();
            grid = transform.GetComponentInChildren<GridLayoutGroup>();
            Content = grid.transform as RectTransform;

            ActiveList = new List<RectTransform>(GetChilds<RectTransform>(Content.transform, false));
            Init();
            SetCurveView();
            scroll.onValueChanged.AddListener(OnValueChange);
        }

        private void TestOffset()
        {
            
            for (int i = 0; i < TestCount; i++)
            {
                GameObject go = Instantiate(Test);
                AddGameObject(go);
            }

            UpdateContent();
            DOTween.To(() => 1500, (w) => { ItemOffset_X = w;SetHeight(); }, 0, 1.5f).SetUpdate(UpdateType.Normal);
        }

        private void Start()
        {
            if (IsTest)
                TestOffset();
            UpdateContent();
            SetStart();
        }


        void  FixedUpdate()
        {
            //SetHeight();
            //UpdateContent();
         
            if (IsTest && Input.GetKeyUp(KeyCode.A))
            {
                if(ActiveList.Count!=0)
                GameObject.Destroy(ActiveList[0].gameObject);
                UpdateContent();
                SetHeight();
            }
        }

  
        public void UpdateContent()
        {
            SetCurveView();
            SetContent();
            SetHeight();
        }

        public void SetStart()
        {
            scroll.horizontalNormalizedPosition = 0;
        }

        private void OnDrawGizmos()
        {
            if(IsEditor)
            TestEditor();
        }

        private void TestEditor()
        {
            Awake();
            UpdateContent();

            for (int i = 0; i < 100; i++)
            {
                Gizmos.color = Color.red;
                Gizmos.DrawSphere(slerp(left, right, 0.01f * i, false, SlerpValue), 0.1f);
            }
            Gizmos.DrawSphere(left, 0.1f);
            Gizmos.DrawSphere(right, 0.1f);
        }

        private void SetCurveView()
        {
            CanvasScale = GameObject.Find("[UI]/UIRoot/UICanvas").transform.localScale.x;
            viewPort = transform.GetChild(0) as RectTransform;
            center = viewPort.position + CenterOffset;
            if (LineCurveWidth == 0)
                LineCurveWidth = viewPort.sizeDelta.x;
            left = center;
            right = center;
            left.x -= LineCurveWidth / 2 * CanvasScale;
            right.x += LineCurveWidth / 2 * CanvasScale;
            CanViewNum =(int) (viewPort.sizeDelta.x / (grid.cellSize.x + grid.spacing.x));
        }

        private void Init()
        {
            scroll.onValueChanged.AddListener(OnValueChange);
        }

        private void SetContent()
        {
            Vector2 size = Content.sizeDelta;
            int count = GetChilds<Transform>(Content,false).Count;
            size.x = count * grid.cellSize.x + grid.spacing.x * (count - 1) + grid.padding.left + grid.padding.right;
            Content.sizeDelta = size;
        }

        private void OnValueChange(Vector2 obj)
        {
            UpdateContent();
            SetHeight();
        }

        private void SetHeight()
        {
            for (int i = 0; i < ActiveList.Count; i++)
            {
                //CurveContainer
                var rt = ActiveList[i].GetChild(0).GetChild(0);
                Vector3 pos = GetPos(rt.position);
                pos.x = rt.position.x;
                rt.position = pos;
                rt.parent.localPosition = new Vector3(ItemOffset_X, 0, 0);
                float p = GetProgressByX(pos.x);
                //角度
                if (p >= 1)
                    continue;
                rt.localEulerAngles = new Vector3(rt.localEulerAngles.x, rt.localEulerAngles.y, (p - 0.5f) * angle);
            }
        }

        /// <summary>
        /// 设置高度以及旋转角度
        /// </summary>
        private Vector3 left;

        private Vector3 right;

        [Range(-10, 10)]
        public float SlerpValue;

        public float angle;

        private float GetProgressByX(float X)
        {
            if (right.x == left.x)
                return 0;
            return (X - left.x) / (right.x - left.x);
        }

        private Vector3 GetPosByProgress(float value)
        {
            Vector3 v = slerp(left, right, value, false, SlerpValue);
            return v;
        }

        private Vector3 GetPos(Vector3 pos)
        {
            float p = GetProgressByX(pos.x);
            return GetPosByProgress(p);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="IsObjectActive">true表示隐藏的也可以获取到</param>
        /// <returns></returns>
        public static List<T> GetChilds<T>(Transform t, bool IsObjectActive = true)
        {
            List<T> list = new List<T>();
            for (int i = 0; i < t.childCount; i++)
            {
                if (IsObjectActive || t.GetChild(i).gameObject.activeInHierarchy)
                    list.Add(t.GetChild(i).GetComponent<T>());
            }
            return list;
        }

        public static Vector3 slerp(Vector3 From, Vector3 To, float value, bool up = true, float slerpvalue = 1)//http://blog.csdn.net/yupu56/article/details/54883003
        {
            float i = up ? 1 : -1;
            Vector3 center = (From + To) * 0.5f;
            center -= Vector3.up * i * slerpvalue;
            var f = From + center * i;
            var t = To + center * i;
            return Vector3.Slerp(f, t, value) - center * i;
        }

        private List<GameObject> SubGoList = new List<GameObject>();

        public GameObject AddGameObject(GameObject go)
        {
            if (!SubGoList.Contains(go))
            {
                SubGoList.Add(go);
            }
            RectTransform Parent = new GameObject("ItemParent").AddComponent<RectTransform>();
            Parent.localPosition = Vector3.zero;
            Parent.transform.SetParent(Content, false);
            RectTransform Offset_X = new GameObject("Offset_X").AddComponent<RectTransform>();
            Offset_X.localPosition = Vector3.zero;
            Offset_X.SetParent(Parent, false);
            RectTransform CurveContainer = new GameObject("CurveContainer").AddComponent<RectTransform>();
            CurveContainer.SetParent(Offset_X, false);
            CurveContainer.localPosition = Vector3.zero;
            go.transform.SetParent(CurveContainer, false);
            UpdateContent();
            AllItemList.Add(Parent);
            ActiveList.Add(Parent);
            return Parent.gameObject;
        }
        public Tweener ShowTween()
        {
            ItemOffset_X = OffSetFrom; SetHeight();
            return DOTween.To(() => OffSetFrom, (w) => { ItemOffset_X = w; SetHeight(); }, 0, 1f).SetEase(Ease.InOutQuad);
        }
        public void RemoveGameObject(GameObject go)
        {
            for (int i = 0; i < SubGoList.Count; i++)
            {
                if (go == SubGoList[i])
                {
                    Destroy(AllItemList[i].gameObject);
                    ActiveList.RemoveAt(i);
                    SubGoList.RemoveAt(i);
                    AllItemList.RemoveAt(i);
                }
            }

            UpdateContent();
        }
        public void ShowGameObject(GameObject go,bool IsShow=true)
        {
            GetParentBySub(go).SetActive(IsShow);
            UpdateContent();
        }

        public GameObject GetParentBySub(GameObject go)
        {
            return go.transform.parent.parent.parent.gameObject;
        }
    }
}